using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using AutoMapper;
using AiPlatformAdmin.Api.Data;
using AiPlatformAdmin.Api.Models;
using AiPlatformAdmin.Api.Services;
using AiPlatformAdmin.Api.DTOs;

namespace AiPlatformAdmin.Api.Controllers;

[ApiController]
[Route("api/[controller]")]
[Authorize(Roles = "Administrator")]
public class UsersController : ControllerBase
{
    private readonly AppDbContext _context;
    private readonly ITenantService _tenantService;
    private readonly IMapper _mapper;
    private readonly IPasswordHasher<User> _passwordHasher;

    public UsersController(
        AppDbContext context, 
        ITenantService tenantService, 
        IMapper mapper,
        IPasswordHasher<User> passwordHasher)
    {
        _context = context;
        _tenantService = tenantService;
        _mapper = mapper;
        _passwordHasher = passwordHasher;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<UserDto>>> GetUsers()
    {
        var users = await _context.Users
            .Include(u => u.UserTeams)
            .ToListAsync();

        return Ok(_mapper.Map<IEnumerable<UserDto>>(users));
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<UserDto>> GetUser(int id)
    {
        var user = await _context.Users
            .Include(u => u.UserTeams)
            .FirstOrDefaultAsync(u => u.Id == id);

        if (user == null)
        {
            return NotFound();
        }

        return Ok(_mapper.Map<UserDto>(user));
    }

    [HttpPost]
    public async Task<ActionResult<UserDto>> CreateUser(CreateUserDto dto)
    {
        if (!_tenantService.CurrentTenantId.HasValue)
        {
            return Forbid();
        }

        // Check if email already exists
        if (await _context.Users.AnyAsync(u => u.Email == dto.Email))
        {
            return BadRequest(new { message = "Email already exists" });
        }

        var user = _mapper.Map<User>(dto);
        user.PasswordHash = _passwordHasher.HashPassword(user, dto.Password);

        _context.Users.Add(user);
        await _context.SaveChangesAsync();

        // Add user to teams
        if (dto.TeamIds != null && dto.TeamIds.Any())
        {
            foreach (var teamId in dto.TeamIds)
            {
                _context.UserTeams.Add(new UserTeam { UserId = user.Id, TeamId = teamId });
            }
            await _context.SaveChangesAsync();
        }

        // Reload with relationships
        await _context.Entry(user).Collection(u => u.UserTeams).LoadAsync();

        return CreatedAtAction(nameof(GetUser), new { id = user.Id }, _mapper.Map<UserDto>(user));
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> UpdateUser(int id, UpdateUserDto dto)
    {
        var user = await _context.Users
            .Include(u => u.UserTeams)
            .FirstOrDefaultAsync(u => u.Id == id);

        if (user == null)
        {
            return NotFound();
        }

        // Check email uniqueness if changed
        if (dto.Email != null && dto.Email != user.Email)
        {
            if (await _context.Users.AnyAsync(u => u.Email == dto.Email && u.Id != id))
            {
                return BadRequest(new { message = "Email already exists" });
            }
        }

        _mapper.Map(dto, user);

        // Update password if provided
        if (!string.IsNullOrEmpty(dto.Password))
        {
            user.PasswordHash = _passwordHasher.HashPassword(user, dto.Password);
        }

        // Update teams if provided
        if (dto.TeamIds != null)
        {
            var existingTeams = user.UserTeams.Select(ut => ut.TeamId).ToList();
            var newTeams = dto.TeamIds.ToList();

            var toAdd = newTeams.Except(existingTeams);
            var toRemove = existingTeams.Except(newTeams);

            foreach (var teamId in toAdd)
            {
                _context.UserTeams.Add(new UserTeam { UserId = id, TeamId = teamId });
            }

            foreach (var teamId in toRemove)
            {
                var teamToRemove = user.UserTeams.FirstOrDefault(ut => ut.TeamId == teamId);
                if (teamToRemove != null)
                {
                    _context.UserTeams.Remove(teamToRemove);
                }
            }
        }

        await _context.SaveChangesAsync();
        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteUser(int id)
    {
        var user = await _context.Users.FindAsync(id);
        if (user == null)
        {
            return NotFound();
        }

        _context.Users.Remove(user);
        await _context.SaveChangesAsync();

        return NoContent();
    }
}
